home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_02_04 / 2n04008a < prev    next >
Text File  |  1991-02-09  |  6KB  |  193 lines

  1. /*
  2.  *  COM.C Copyright (C) 1990 by Mark R. Nelson
  3.  *
  4.  * This module contains a complete interface to a multiport RS-232 board.
  5.  * It is presently configured for the Stargate Plus 4 board.
  6.  */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <dos.h>
  10. #include <conio.h>
  11. #include "com.h"
  12.  
  13. void interrupt far interrupt_service_routine( void );
  14. static BOARD board;
  15.  
  16. /*
  17.  * This routine opens a multiport board up.  It initializes the data
  18.  * structure associated with the board, mostly from parameters passed
  19.  * by the caller.  It needs to make a DOS call with getvect to get
  20.  * the old interrupt vector for the board, then another call to
  21.  * setvect to connect our interrupt_service_routine to the vector.
  22.  */
  23. BOARD *board_open( unsigned int address, unsigned char int_number )
  24. {
  25.     unsigned char temp_port;
  26.  
  27.     board.status_address = address;
  28.     board.irq_mask = (char) 1 << (int_number % 8 );
  29.     board.int_number = int_number;
  30.     board.port_count = 0;
  31.     board.old_vector = getvect( int_number );
  32.     setvect( int_number, interrupt_service_routine );
  33. /*
  34.  * These two lines instruct the 8259 interrupt controller to start
  35.  * accepting interrupts from the multiport board.
  36.  */
  37.     temp_port = (char) inportb( 0x21 );
  38.     outportb( 0x21, ~board.irq_mask & temp_port );
  39. /*
  40.  * Return a pointer to the structure.
  41.  */
  42.     return( &board );
  43. }
  44.  
  45. /*
  46.  * This routine is called to set up a data structure and open a port
  47.  * on a board that should have already been opened.
  48.  */
  49.  
  50. PORT *port_open( BOARD *board, unsigned int address, unsigned char match )
  51. {
  52.     PORT *port;
  53.  
  54.     if ((port = malloc( sizeof( PORT ))) == NULL)
  55.    return( NULL );
  56.     port->head = 0;
  57.     port->tail = 0;
  58.     port->match = match;
  59.     port->address = address;
  60.     board->ports[ board->port_count++ ] = port;
  61.     return(port);
  62. }
  63.  
  64. /*
  65.  * This routine sets up the transmission parameters for the UART.  See
  66.  * the data sheet for details on what is going on here.  Finally, it
  67.  * enables interrupts so the port can start receiving.
  68.  */
  69. void port_set( PORT *port, long speed, char parity, int data, int stopbits )
  70. {
  71.     unsigned char temp_port;
  72. /*
  73.  * First write the new baud rate to the UART.
  74.  */
  75.     outportb( port->address + 3, 0x80 );
  76.     outportb( port->address, (char)(115200L / speed ) & 0xff );
  77.     outportb( port->address + 1, (char)(115200L /  speed ) >> 8 );
  78. /*
  79.  * Set up line control register.
  80.  */
  81.     if ( parity== 'E' )
  82.    temp_port = 0x8;        /* Set bit 3 on for even parity */
  83.     else if ( parity == 'O' )
  84.    temp_port = 0x18;
  85.     else
  86.    temp_port = 0;
  87.  
  88.     if ( stopbits == 2 )
  89.    temp_port |= 0x4;
  90.  
  91.     if ( data == 6 )
  92.    temp_port |= 0x1;
  93.     else if ( data == 7 )
  94.    temp_port |= 0x2;
  95.     else if ( data == 8 )
  96.    temp_port |= 0x3;
  97.  
  98.     outportb( port->address + 3, temp_port );
  99. /*
  100.  * Turn on OUT2, RTS & DTR.  OUT2 is necessary on the PC for
  101.  * interrupts to take effect.
  102.  */
  103.     outportb( port->address + 4, 0xb );
  104. /*
  105.  * Then enable receiver interrupts.
  106.  */
  107.     outportb( port->address + 1, 0x1 );
  108. }
  109.  
  110. /*
  111.  * This routine closes a board by disabling interrupts for that line
  112.  * and restoring the old interrupt vector.  It also closes any ports
  113.  * that were left open.
  114.  */
  115. void board_close( BOARD *board )
  116. {
  117.     unsigned char temp_port;
  118.     unsigned int i;
  119.  
  120.     for ( i = 0 ; i < board->port_count ; i++ )
  121.    port_close( board->ports[ i ] );
  122.     temp_port = (unsigned char) inportb( 0x21 );
  123.     outportb( 0x21, board->irq_mask | temp_port);
  124.     setvect( board->int_number, board->old_vector );
  125. }
  126.  
  127. /*
  128.  * This routine closes a port.  All this means is disabling receiver
  129.  * interrupts, then freeing up the structure.  Note that this routine
  130.  * should probably not be called by the user, it should be left up
  131.  * to board_close() to close all the ports.
  132.  */
  133. void port_close( PORT *port )
  134. {
  135.     outportb( port->address + 1, 0x0 );
  136.     free( port );
  137. }
  138.  
  139. /*
  140.  * port_putc() is used to output a single character through the given
  141.  * port.  This is done by just wainting for the transmit holding register
  142.  * to be empty, then writing the character to the UART.
  143.  */
  144. void port_putc( PORT *port, unsigned char c )
  145. {
  146.     while( (inportb(port->address+5) & 0x20) == 0 )
  147.    ;
  148.     outportb(port->address,c);
  149. }
  150.  
  151. /*
  152.  * port_getc() checks to see if there are any characters in the port's
  153.  * input buffer.  If there are, the oldest one is pulled out and
  154.  * returned, otherwise an error code is returned.  Note that the code
  155.  * is simplified by having a byte index and a 256 byte buffer.
  156.  */
  157. int port_getc(PORT *port)
  158. {
  159.     if ( port->head == port->tail )
  160.    return( -1 );
  161.     else
  162.    return( port->buffer[ port->tail++ ] );
  163. }
  164.  
  165. /*
  166.  * The interrupt service routine has to read in the status register,
  167.  * then figure out which port(s) have characters to be read.
  168.  * The characters are read in, and stuffed into the buffers.
  169.  */
  170. void interrupt far interrupt_service_routine()
  171. {
  172.     int i;
  173.     unsigned char status_reg;
  174.     PORT *port;
  175.  
  176.     status_reg = (unsigned char) inportb( board.status_address );
  177.     for ( i = 0 ; i < board.port_count ; i++ )
  178.     {
  179.  if ( board.ports[i]->match & status_reg ) {
  180.    port=board.ports[ i ];
  181.    port->buffer[ port->head ] = (unsigned char) inportb(port->address);
  182.    if ((port->head + 1 ) != port->tail)
  183.      port->head++;
  184.  }
  185.     }
  186. /*
  187.  * This line sends the EOI signal to the interrupt controller, letting it
  188.  * know that we are done.
  189.  */
  190.     outportb(0x20,0x20);
  191. }
  192.  
  193.